package com.framework.service.module.job.impl;

import com.alibaba.fastjson.JSONObject;
import com.framework.common.enums.job.JobDataKeyEnum;
import com.framework.common.enums.result.ResultEnum;
import com.framework.common.model.response.R;
import com.framework.common.util.cron.CronUtils;
import com.framework.common.util.other.NumeralUtil;
import com.framework.common.util.redis.RedisKeyUtil;
import com.framework.common.util.system.ApplicationContextUtil;
import com.framework.mapper.module.job.ScheduledTasksMapper;
import com.framework.model.module.job.vo.ScheduledTasksVo;
import com.framework.model.system.vo.SystemUserVo;
import com.framework.service.base.BaseService;
import com.framework.service.module.job.ScheduledTasksService;
import java.util.Date;
import java.util.List;
import com.framework.service.timedTask.JobHandlerService;
import com.framework.service.timedTask.impl.JobHandlerInvoker;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author 龘鵺
 * @version 1.0
 * @className com.framework.service.module.job.impl.ScheduledTasksServiceImpl
 * @description 定时任务业务接口实现类
 * @datetime 2025-04-24 15:09:24
 */
@Service("scheduledTasksServiceImpl")
public class ScheduledTasksServiceImpl extends BaseService implements ScheduledTasksService {
    private Logger log = LoggerFactory.getLogger(ScheduledTasksServiceImpl.class);
    @Autowired
    private ScheduledTasksMapper scheduledTasksMapper;
    @Autowired
    private Scheduler scheduler;

    /**
     * @param id 1 编号
     * @return com.framework.model.module.job.vo.ScheduledTasksVo
     * @title 根据编号查询定时任务
     * @description 根据编号查询定时任务
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    public ScheduledTasksVo getByIdParam(Long id) {
        ScheduledTasksVo row = new ScheduledTasksVo();
        row.setId(id);
        row.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ONE);
        ScheduledTasksVo p = scheduledTasksMapper.selectByParam(row);
        if (p == null) {
            return new ScheduledTasksVo();
        }
        return p;
    }

    /**
     * @param id 1 编号
     * @return com.framework.model.module.job.vo.ScheduledTasksVo
     * @title 根据编号查询定时任务 - 查看专用
     * @description 根据编号查询定时任务 - 查看专用
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    public ScheduledTasksVo getByIdParamView(Long id) {
        ScheduledTasksVo row = new ScheduledTasksVo();
        row.setId(id);
        row.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ONE);
        ScheduledTasksVo p = scheduledTasksMapper.selectByParam(row);
        if (p == null) {
            return new ScheduledTasksVo();
        }
        p.setCronDateList(CronUtils.getNextTimes(p.getCronExpression(), NumeralUtil.POSITIVE_SIX));
        return p;
    }

    /**
     * @param row 1 定时任务类
     * @return java.util.List<com.framework.model.module.job.vo.ScheduledTasksVo>
     * @title 查询定时任务集合
     * @description 查询定时任务集合
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    public List<ScheduledTasksVo> findByList(ScheduledTasksVo row) {
        row.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ONE);
        List<ScheduledTasksVo> list = scheduledTasksMapper.findByList(row);
        return list;
    }

    /**
     * @param row 1 定时任务类
     * @return com.framework.common.model.response.R
     * @title 分页查询定时任务列表
     * @description 分页查询定时任务列表
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    public R<?> findParamPageList(ScheduledTasksVo row) {
        row.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ONE);
        int count = scheduledTasksMapper.findPageListCount(row);
        if (count == NumeralUtil.POSITIVE_ZERO) {
            return R.ok();
        }
        List<ScheduledTasksVo> list = scheduledTasksMapper.findPageList(row);
        return R.ok(list, count);
    }

    /**
     * @param row 1 定时任务类
     * @return com.framework.common.model.response.R
     * @title 新增定时任务
     * @description 新增定时任务
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    @Transactional
    public R<?> save(ScheduledTasksVo row) throws Exception {
        row.setId(null);
        boolean isExistBean = ApplicationContextUtil.isExistBean(row.getCode());
        if (!isExistBean) {
            return R.fail("任务编码不存在!");
        }
        Object object = ApplicationContextUtil.getBean(row.getCode());
        if (!(object instanceof JobHandlerService)) {
            return R.fail("任务编码错误!");
        }
        int num = scheduledTasksMapper.isExist(row);
        if (num > NumeralUtil.POSITIVE_ZERO) {
            return R.fail(ResultEnum.CODE3000);
        }
        if (!CronExpression.isValidExpression(row.getCronExpression())) {
            return R.fail("CRON表达式错误");
        }
        if (StringUtils.isNotEmpty(row.getParam())) {
            try {
                JSONObject.parseObject(row.getParam());
            } catch (Exception e) {
                return R.fail("任务参数必须JSON格式");
            }
        }
        SystemUserVo systemUserVo = getUser();
        Long userId = systemUserVo.getId();
        Date date = new Date();
        row.setCreateId(userId);
        row.setCreateTime(date);
        row.setOperaterId(userId);
        row.setOperaterTime(date);
        row.setOperaterStatus(NumeralUtil.POSITIVE_ONE);
        scheduledTasksMapper.insertSelective(row);
        if (row.getEnableStatus().intValue() == NumeralUtil.POSITIVE_ONE) {
            // 创建 JobDetail 对象
            JobDetail jobDetail = this.buildJobDetail(row);
            // 创建 Trigger 对象
            /**
             * CronExpression
             * 0 0/2 * * * ? 正确 必须最后一位是问号，会出现无效错误 每2分钟执行一次
             * 0/20 * * * * ? 正确 必须最后一位是问号，会出现无效错误 每20秒执行一次
             * 0 0/2 * * * * 错误 最后一位没问号，无效错误
             */
            Trigger trigger = this.buildTrigger(row);
            // 新增 Job 调度
            scheduler.scheduleJob(jobDetail, trigger);
        }
        return R.ok();
    }

    private JobDetail buildJobDetail(ScheduledTasksVo row) {
        return JobBuilder.newJob(JobHandlerInvoker.class)
                .usingJobData(JobDataKeyEnum.JOB_ID.name(), row.getId())
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), row.getName())
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_CODE.name(), row.getCode())
                .withIdentity(row.getCode()).build();
    }

    private Trigger buildTrigger(ScheduledTasksVo row) {
        return TriggerBuilder.newTrigger()
                .withIdentity(row.getCode())
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_CODE.name(), row.getCode())
                .withSchedule(CronScheduleBuilder.cronSchedule(row.getCronExpression()))
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), row.getParam())
                .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), row.getRetryCount())
                .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), row.getRetryInterval())
                .build();
    }

    private Trigger buildTrigger(String jobHandlerName, String jobHandlerCode, String jobHandlerParam, String cronExpression,
                                 Integer retryCount, Integer retryInterval) {
        return TriggerBuilder.newTrigger()
                .withIdentity(jobHandlerName)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_CODE.name(), jobHandlerCode)
                .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount)
                .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval)
                .build();
    }

    /**
     * @param row 1 定时任务类
     * @return com.framework.common.model.response.R
     * @title 编辑定时任务
     * @description 编辑定时任务
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    @Transactional
    public R<?> edit(ScheduledTasksVo row) throws Exception {
        boolean isExistBean = ApplicationContextUtil.isExistBean(row.getCode());
        if (!isExistBean) {
            return R.fail("任务编码不存在!");
        }
        Object object = ApplicationContextUtil.getBean(row.getCode());
        if (!(object instanceof JobHandlerService)) {
            return R.fail("任务编码错误!");
        }
        int num = scheduledTasksMapper.isExist(row);
        if (num > NumeralUtil.POSITIVE_ZERO) {
            return R.fail(ResultEnum.CODE3000);
        }
        ScheduledTasksVo queryParam = scheduledTasksMapper.selectByPrimaryKey(row.getId());
        if (queryParam == null) {
            return R.fail("编辑信息不存在!");
        }
        if (!CronExpression.isValidExpression(row.getCronExpression())) {
            return R.fail("CRON表达式错误");
        }
        SystemUserVo systemUserVo = getUser();
        Long userId = systemUserVo.getId();
        Date date = new Date();
        row.setOperaterTime(date);
        row.setOperaterId(userId);
        row.setOperaterStatus(NumeralUtil.POSITIVE_TWO);
        scheduledTasksMapper.updateByPrimaryKeySelective(row);
        if (row.getEnableStatus().intValue() == NumeralUtil.POSITIVE_ONE) {
            // 创建 Trigger 对象
            Trigger newTrigger = this.buildTrigger(row);
            if (!queryParam.getCode().equalsIgnoreCase(row.getCode())) {
                /**
                 * 删除旧code定时任务
                 */
                // 暂停 Trigger 对象
                scheduler.pauseTrigger(new TriggerKey(queryParam.getCode()));
                // 取消 Job 调度
                scheduler.unscheduleJob(new TriggerKey(queryParam.getCode()));
                // 删除 Job 调度
                scheduler.deleteJob(new JobKey(queryParam.getCode()));
                /**
                 * 创建新code定时任务
                 */
                // 创建 JobDetail 对象
                JobDetail jobDetail = this.buildJobDetail(row);
                // 创建 Trigger 对象
                /**
                 * CronExpression
                 * 0 0/2 * * * ? 正确 必须最后一位是问号，会出现无效错误 每2分钟执行一次
                 * 0/20 * * * * ? 正确 必须最后一位是问号，会出现无效错误 每20秒执行一次
                 * 0 0/2 * * * * 错误 最后一位没问号，无效错误
                 */
                Trigger trigger = this.buildTrigger(row);
                // 新增 Job 调度
                scheduler.scheduleJob(jobDetail, trigger);
            } else {
                // 修改调度
                scheduler.rescheduleJob(new TriggerKey(row.getCode()), newTrigger);
            }
        } else {
            // 停止调度任务
            scheduler.pauseJob(new JobKey(row.getCode()));
            // 暂停 Trigger 对象
            scheduler.pauseTrigger(new TriggerKey(row.getCode()));
        }
        return R.ok();
    }

    /**
     * @param id 1 编号
     * @return com.framework.common.model.response.R
     * @title 删除定时任务
     * @description 删除定时任务
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    @Transactional
    public R<?> delete(Long id) throws Exception {
        ScheduledTasksVo queryRow = new ScheduledTasksVo();
        queryRow.setId(id);
        queryRow.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ZERO);
        queryRow = scheduledTasksMapper.selectByParam(queryRow);
        if (queryRow == null) {
            return R.fail("信息不存在!");
        }
        ScheduledTasksVo row = new ScheduledTasksVo();
        Date date = new Date();
        SystemUserVo systemUserVo = getUser();
        Long userId = systemUserVo.getId();
        row.setId(id);
        row.setOperaterTime(date);
        row.setOperaterId(userId);
        row.setOperaterStatus(NumeralUtil.NEGATIVE_ONE);
        scheduledTasksMapper.delete(row);
        // 暂停 Trigger 对象
        scheduler.pauseTrigger(new TriggerKey(queryRow.getCode()));
        // 取消 Job 调度
        scheduler.unscheduleJob(new TriggerKey(queryRow.getCode()));
        // 删除 Job 调度
        scheduler.deleteJob(new JobKey(queryRow.getCode()));
        return R.ok();
    }

    /**
     * @param idList 1 编号集合
     * @return com.framework.common.model.response.R
     * @title 批量删除定时任务
     * @description 批量删除定时任务
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    @Transactional
    public R<?> batchDeleteList(List<Long> idList) throws Exception {
        ScheduledTasksVo row = new ScheduledTasksVo();
        SystemUserVo systemUserVo = getUser();
        Long userId = systemUserVo.getId();
        Date date = new Date();
        row.setIdList(idList);
        row.setOperaterTime(date);
        row.setOperaterId(userId);
        row.setOperaterStatus(NumeralUtil.NEGATIVE_ONE);
        //scheduledTasksMapper.deleteList(row);
        return R.ok();
    }

    /**
     * @param id 1 编号
     * @return com.framework.common.model.response.R
     * @title 启用|禁用，定时任务
     * @description 启用|禁用，定时任务
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    @Transactional
    public R<?> enable(Long id) throws Exception {
        String timeKey = RedisKeyUtil.getObjKey("SCHEDULED_TASKS_ENABLE_KEY", "SCHEDULED_TASKS_ENABLE_KEY", id.toString());
        long expireNum = redisUtil.getExpire(timeKey);
        if (expireNum > NumeralUtil.POSITIVE_ZERO) {
            return R.fail("操作频繁,请" + expireNum + "秒后重试!");
        }
        ScheduledTasksVo row = new ScheduledTasksVo();
        SystemUserVo systemUserVo = getUser();
        Long userId = systemUserVo.getId();
        row.setId(id);
        row.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ZERO);
        row = scheduledTasksMapper.selectByParam(row);
        if (row == null) {
            return R.fail("信息不存在!");
        }
        redisUtil.setString(timeKey, NumeralUtil.STRING_POSITIVE_ZERO, NumeralUtil.POSITIVE_THIRTY);
        Date date = new Date();
        ScheduledTasksVo updateRow = new ScheduledTasksVo();
        updateRow.setId(id);
        updateRow.setOperaterId(userId);
        updateRow.setOperaterTime(date);
        updateRow.setOperaterStatus(NumeralUtil.POSITIVE_TWO);
        updateRow.setEnableStatus(row.getEnableStatus().intValue() == NumeralUtil.POSITIVE_TWO ? NumeralUtil.POSITIVE_ONE : NumeralUtil.POSITIVE_TWO);
        scheduledTasksMapper.updateByPrimaryKeySelective(updateRow);
        if (row.getEnableStatus().intValue() == NumeralUtil.POSITIVE_TWO) {
//            updateRow.setEnableStatus(NumeralUtil.POSITIVE_ONE);
            // 启用调度任务
            scheduler.resumeJob(new JobKey(row.getCode()));
            // 启用触发任务
            scheduler.resumeTrigger(new TriggerKey(row.getCode()));
        } else {
//            updateRow.setEnableStatus(NumeralUtil.POSITIVE_TWO);
            // 停止调度任务
            scheduler.pauseJob(new JobKey(row.getCode()));
////            // 停止触发任务
//            scheduler.pauseTrigger(new TriggerKey(row.getCode()));
        }
        return R.ok();
    }

    /**
     * @param id 1 编号
     * @return com.framework.common.model.response.R
     * @title 执行一次
     * @description 执行一次
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    public R<?> executeOne(Long id) throws Exception {
        String timeKey = RedisKeyUtil.getObjKey("SCHEDULED_TASKS_EXECUTE_ONE_KEY", "SCHEDULED_TASKS_EXECUTE_ONE_KEY", id.toString());
        long expireNum = redisUtil.getExpire(timeKey);
        if (expireNum > NumeralUtil.POSITIVE_ZERO) {
            return R.fail("操作频繁,请" + expireNum + "秒后重试!");
        }
        ScheduledTasksVo row = new ScheduledTasksVo();
        row.setId(id);
        row.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ZERO);
        row = scheduledTasksMapper.selectByParam(row);
        if (row == null) {
            return R.fail("信息不存在!");
        }
        redisUtil.setString(timeKey, NumeralUtil.STRING_POSITIVE_ZERO, NumeralUtil.POSITIVE_SIXTY);
        // 触发任务
        JobDataMap data = new JobDataMap(); // 无需重试，所以不设置 retryCount 和 retryInterval
        data.put(JobDataKeyEnum.JOB_ID.name(), row.getId());
        data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), row.getName());
        data.put(JobDataKeyEnum.JOB_HANDLER_CODE.name(), row.getCode());
        data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), row.getParam());
        scheduler.triggerJob(new JobKey(row.getCode()), data);
        return R.ok();
    }

    /**
     * @return com.framework.common.model.response.R
     * @title 重置所有
     * @description 重置所有
     * @author 龘鵺
     * @datetime 2025-04-24 15:09:24
     * @version 1.0
     */
    @Override
    public R<?> reset() throws Exception {
        String timeKey = RedisKeyUtil.getObjKey("SCHEDULED_TASKS_RESET_KEY", "SCHEDULED_TASKS_RESET_KEY", "reset");
        long expireNum = redisUtil.getExpire(timeKey);
        if (expireNum > NumeralUtil.POSITIVE_ZERO) {
            return R.fail("操作频繁,请" + expireNum + "秒后重试!");
        }
        redisUtil.setString(timeKey, NumeralUtil.STRING_POSITIVE_ZERO, NumeralUtil.POSITIVE_ONE_HUNDRED_EIGHT);
        ScheduledTasksVo scheduledTasksVo = new ScheduledTasksVo();
//        scheduledTasksVo.setEnableStatus(NumeralUtil.POSITIVE_ONE);
        scheduledTasksVo.setGtaeOperaterStatus(NumeralUtil.POSITIVE_ONE);
        List<ScheduledTasksVo> scheduledTasksVoList = scheduledTasksMapper.findByList(scheduledTasksVo);
        // 遍历处理
        for (ScheduledTasksVo item : scheduledTasksVoList) {
            /**
             * 先删除
             */
            // 暂停 Trigger 对象
            scheduler.pauseTrigger(new TriggerKey(item.getCode()));
            // 取消 Job 调度
            scheduler.unscheduleJob(new TriggerKey(item.getCode()));
            // 删除 Job 调度
            scheduler.deleteJob(new JobKey(item.getCode()));
            /**
             * 再创建
             */
            // 创建 JobDetail 对象
            JobDetail jobDetail = this.buildJobDetail(item);
            // 创建 Trigger 对象
            /**
             * CronExpression
             * 0 0/2 * * * ? 正确 必须最后一位是问号，会出现无效错误 每2分钟执行一次
             * 0/20 * * * * ? 正确 必须最后一位是问号，会出现无效错误 每20秒执行一次
             * 0 0/2 * * * * 错误 最后一位没问号，无效错误
             */
            Trigger trigger = this.buildTrigger(item);
            // 新增 Job 调度
            scheduler.scheduleJob(jobDetail, trigger);
            /**
             * 如果 EnableStatus 为暂停，则需要暂停
             */
            if (item.getEnableStatus().intValue() == NumeralUtil.POSITIVE_TWO) {
                // 停止调度任务
                scheduler.pauseJob(new JobKey(item.getCode()));
            }
            log.info("ScheduledTasksServiceImpl.reset", item.getName(), item.getCode());
        }
        return R.ok();
    }


}